/**
 * Created by lintao_alex on 2017/10/17.
 */


namespace game{
    import EgretFactory = dragonBones.EgretFactory;
    import ByteArray = egret.ByteArray;
    import BitmapData = egret.BitmapData;
    import Texture = egret.Texture;
    import EgretArmatureDisplay = dragonBones.EgretArmatureDisplay;
    import Slot = dragonBones.Slot;

    export class SkeletonManager{
        get dbFactory():dragonBones.EgretFactory{
            return this._dbFactory;
        }
        static getSkeResNames(orgList:string[]){
            let out:string[] = [];
            for(let i = orgList.length - 1; i >= 0; i--){
                let org = orgList[i];
                out.push(org+'_sked')
                out.push(org+'_tex_png')
            }
            return out;
        }
        private _skeMap:Map<string, SkePrepareNode>
        private _dbFactory:EgretFactory;

        public constructor(){
            this._dbFactory = EgretFactory.factory;
            this._skeMap = new Map<string, SkePrepareNode>();
        }

        // public buildArmatureByCfg(skeCfg:HeroSkeletonClient):EgretArmatureDisplay{
        //     return this.buildArmatureDisplay(skeCfg.armature, skeCfg.skeleton, skeCfg.replaceArmature);
        // }

        public buildArmatureDisplay(armature:string, skeletonRes:string, replaceArmature?:string):EgretArmatureDisplay{
            let factory = this._dbFactory;
            if(replaceArmature){
                let out = factory.buildArmatureDisplay(replaceArmature, skeletonRes);
                factory.copyAnimationsToArmature(out.armature, armature, null, skeletonRes);
                return out;
            }else{
                return factory.buildArmatureDisplay(armature, skeletonRes);
            }
        }

        public prepareSkeList(skeList:string[], finCall:Function, callObj:any, ...args){
            let cnt = skeList.length;
            let oneCall = ()=>{
                if(--cnt==0){
                    finCall.apply(callObj, args)
                }
            }
            for(let ske of skeList){
                this.prepareSke(ske, oneCall, this)
            }
        }

        public prepareSke(skeName:string, finCall:Function, callObj:any, ...args){
            let hasNode = this._skeMap.has(skeName);
            if(hasNode){
                var node = this._skeMap.get(skeName);
            }else{
                node = new SkeNoPicPrepareNode(skeName, this._dbFactory);
                this._skeMap.set(skeName, node);
            }
            if(node.couldBuild){
                finCall.apply(callObj, args);
            }else{
                node.finCallList.addCall(finCall, callObj, ...args);
            }
            if(!hasNode){
                node.loadRes();
            }
        }

        private static _instance:SkeletonManager;
        public static get instance():SkeletonManager{
            if(!SkeletonManager._instance){
                SkeletonManager._instance = new SkeletonManager();
            }
            return SkeletonManager._instance;
        }

        // public static getHeroSkeletonConfig(id:number, type:number=1):HeroSkeletonClient{
        //     return StaticDataUtils.getDataByKeys(HeroSkeletonClient,['heroId', id], ['heroType', type])
        // }

        private static _replaceTexIdx = 0;
        static replaceSlotTexture(slot:Slot, texture:egret.Texture){
            let name = 'textureForReplace'+(this._replaceTexIdx++);
            let tran:any;
            if(slot['_displayData']){
                let disTran = slot['_displayData'].transform;
                tran = {scX:disTran.scaleX,scY:disTran.scaleY,x:disTran.x, y:disTran.y}
                tran.skX = tran.skY = 180*disTran.rotation/Math.PI;
            }
            SkeletonMaker.parseTexture(texture, name, tran);
            this.instance.dbFactory.replaceSlotDisplay(name, SkeletonMaker.armatureName, SkeletonMaker.slotName, name, slot);
        }

    }

    class SkePrepareNode{
        readonly key:string;
        readonly finCallList:BackCallArgsList;
        /**0：加载及处理过程中，1：处理完成*/
        private _state:number;
        private _factory:EgretFactory;

        public constructor(key:string, factory?:EgretFactory){
            this.key = key;
            this.finCallList = new BackCallArgsList();
            this._state = 0;
            if(factory) this._factory = factory;
            else this._factory = EgretFactory.factory;
        }

        public loadRes(){
            if(this._state!=0) return;
            this.doLoadRes();
        }

        protected doLoadRes(){
            let resKey = this.key + '_ske';
            RES.getResAsync(resKey, this.gotRes, this);
        }

        private gotRes(orgBuff:ArrayBuffer){
            let inflater = new Zlib.RawInflate(orgBuff)
            let data:Uint8Array = inflater.decompress();
            let arr = data.buffer
            let view = new DataView(arr)
            let pos = 0;
            let len = view.getUint32(pos, false)
            pos += 4;
            let dbbin = arr.slice(pos, pos+len)

            pos += len;
            len = view.getUint32(pos, false)
            pos += 4;
            let json = arr.slice(pos, pos+len)
            let jsonStr = (new ByteArray(json)).readUTFBytes(len)

            pos += len;
            len = view.getUint32(pos, false)
            pos += 4;
            let png = arr.slice(pos, pos+len)
            let pngBit = BitmapData.create('arraybuffer', png)
            let pngSource:HTMLImageElement = pngBit.source;
            if(pngSource.onload){
                let sourceLoad = pngSource.onload;
                pngSource.onload = ()=>{
                    sourceLoad.apply(pngSource)
                    this.buildSke(dbbin, jsonStr, pngBit);
                }
            }else{
                this.buildSke(dbbin, jsonStr, pngBit);
            }
        }

        private buildSke(dbbin:any, jsonStr:string, bitData:BitmapData){
            let tex = new Texture();
            tex._setBitmapData(bitData);
            this.finalBuildSke(dbbin, jsonStr, tex);
        }

        protected finalBuildSke(dbbin:any, jsonStr:string, tex:Texture){
            let jsonObj = JSON.parse(jsonStr);
            let factory = this._factory;
            factory.parseDragonBonesData(dbbin);
            factory.parseTextureAtlasData(jsonObj, tex);
            this._state = 1;
            this.finCallList.invoke();
        }

        get couldBuild():boolean{
            return this._state == 1;
        }
    }

    //图片不压缩的版本
    class SkeNoPicPrepareNode extends SkePrepareNode{
        private _ske:ArrayBuffer|null;
        private _pic:Texture|null;

        protected doLoadRes():void{
            RES.getResAsync(this.key + '_sked', this.gotSke, this);
            RES.getResAsync(this.key + '_tex_png', this.gotPic, this);
        }

        private gotPic(tex:Texture){
            this._pic = tex;
            if(this._ske){
                this.convertData();
            }
        }

        private gotSke(ske:ArrayBuffer){
            this._ske = ske;
            if(this._pic){
                this.convertData();
            }
        }

        private convertData(){
            let ske = this._ske;
            let pic = this._pic;
            this._ske = null;
            this._pic = null;

            let inflater = new Zlib.RawInflate(ske)
            let data:Uint8Array = inflater.decompress();
            let arr = data.buffer
            let view = new DataView(arr)
            let pos = 0;
            let len = view.getUint32(pos, false)
            pos += 4;
            let dbbin = arr.slice(pos, pos+len)

            pos += len;
            len = view.getUint32(pos, false)
            pos += 4;
            let json = arr.slice(pos, pos+len)
            let jsonStr = (new ByteArray(json)).readUTFBytes(len)

            this.finalBuildSke(dbbin, jsonStr, pic);
        }
    }
}